﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
using DocumentFormat.OpenXml.Packaging;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using TemplateLibraryConnector.Data;

namespace TemplateLibraryConnector
{
    public class ThumbNail : IHttpHandler
    {

        string sNoThumbPath = NoPreviewAvailableFile("");
        private int width = 0;
        private int height = 0;

        private static string NoPreviewAvailableFile(string fileName)
        {
            if( !string.IsNullOrEmpty(fileName))
                return HttpContext.Current.Request.MapPath("/_layouts/15/images/"  + SPUtility.MapToIcon(SPContext.Current.Web, fileName,"", IconSize.Size32));
            else
            {
                return HttpContext.Current.Request.MapPath("/_layouts/15/images/erroricon.png");
            }
        }

        //Keeps the IHttpHandler in memory, so as not to instantiate it on every request.
        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            try
            {
                width = context.Request["width"] != null ? Int32.Parse(context.Request["width"]) : -1;
                height = context.Request["height"] != null ? Int32.Parse(context.Request["height"]) : -1;


                if (context.Request["FilePath"] != null)
                {
                    var path = (context.Request["FilePath"]);

                    using (var templateHubSite = TemplateLibraryDataUtility.GetDocumentLibrarySite(path))
                    {
                        using (var templateHubWeb = TemplateLibraryDataUtility.GetDocumentLibraryWeb(path, templateHubSite))
                        {
                            var item = templateHubWeb.GetListItem(path);
                            var fileExt = Path.GetExtension(item.File.Name.ToLower());
                            sNoThumbPath = NoPreviewAvailableFile(path);
                            var fileStream = item.File.OpenBinaryStream(SPOpenBinaryOptions.SkipVirusScan);

                            //Checks for all office XML file extensions
                            switch (fileExt)
                            {
                                //Word Document
                                case ".docx":
                                //Macro-enabled Word document
                                case ".docm":
                                    {
                                        UpdateWordThumbnails(fileStream);
                                        break;
                                    }

                                //Word Template
                                case ".dotx":
                                //Macro-enabled Word template
                                case ".dotm":
                                    {
                                        UpdateWordTemplateThumbnails(fileStream);
                                        break;
                                    }

                                //Powerpoint Presentation
                                case ".pptx":
                                //Macro-enabled Powerpoint Presentation
                                case ".pptm":
                                //Powerpoint Template
                                case ".potx":
                                //Macro-enabled Powerpoint Template
                                case ".potm":
                                //Macro-enabled Powerpoint add-in
                                case ".ppam":
                                //Powerpoint Show
                                case ".ppsx":
                                //Macro-enabled Powerpoint Show
                                case ".ppsm":
                                //Powerpoint Slide
                                case ".sldx":
                                //Macro-enabled Powerpoint Slide
                                case ".sldm":
                                //Office Theme
                                case ".thmx":
                                    {
                                        UpdatePowerPointThumbnails(fileStream);
                                        break;
                                    }

                                //Excel Workbook
                                case ".xlsx":
                                //Macro-enabled Excel Workbook
                                case ".xlsm":
                                //Excel Template
                                case ".xltx":
                                //Macro-enabled Excel Template
                                case ".xltm":
                                //Excel Non-XML binary workbook (untested, will most likely bomb)
                                case ".xlsb":
                                //Macro-enabled Excel add-in
                                case ".xlam":
                                    {
                                        UpdateExcelThumbnails(fileStream);
                                        break;
                                    }
                                default:
                                    {
                                        Image thumbBitmap = new Bitmap(sNoThumbPath);
                                        
                                        SaveImageToHttpStream(thumbBitmap);
                                        break;
                                    }

                            }
                        }
                    }
                }
                else
                {
                    Image thumbBitmap = new Bitmap(sNoThumbPath);

                    if (context.Request["thumb"] != null && context.Request["thumb"] == "no")
                    {
                        SaveImageToHttpStream(thumbBitmap);
                    }
                    else
                    {
                        if (width != -1 && width < thumbBitmap.Width)
                            thumbBitmap = ResizeImage(width, thumbBitmap);
                        
                        SaveImageToHttpStream(thumbBitmap);
                    }
                }
            }
            catch (SPException ex)
            {
                TemplateLibraryConnector.Utility.ULSLogger.LogError("Error in Thnumbnail.ashx", ex); 

            }
            catch (Exception e)
            {
                TemplateLibraryConnector.Utility.ULSLogger.LogError("Error in Thnumbnail.ashx", e); 

            }
            
        }
            

        private void UpdateThumbnail(ThumbnailPart tn, ThumbnailPartType tnType)
        {
            Image sourceThumbnail;
            if (tn != null)
            {
                var thumbnailStream = tn.GetStream(FileMode.Open, FileAccess.Read);
                
                if (tnType == ThumbnailPartType.Emf || tnType == ThumbnailPartType.Wmf)
                    sourceThumbnail = new Metafile(thumbnailStream);
                else
                    sourceThumbnail = new Bitmap(thumbnailStream);
            }
            else
            {
                sourceThumbnail = new Bitmap(sNoThumbPath);
            }

            if (width != -1 && width < sourceThumbnail.Width)
                sourceThumbnail = ResizeImage(width, sourceThumbnail);

            SaveImageToHttpStream(sourceThumbnail);

        }

        private static void SaveImageToHttpStream(Image sourceThumbnail)
        {
            // Get the PNG image codec
            ImageCodecInfo codec = GetCodec("image/png");

            // Configure to encode at high quality
            using (EncoderParameters ep = new EncoderParameters())
            {
                ep.Param[0] = new EncoderParameter(Encoder.Quality, 100L);

                // Encode the image
                using (MemoryStream ms = new MemoryStream())
                {
                    sourceThumbnail.Save(ms, codec, ep);

                    // Send the encoded image to the browser
                    HttpContext.Current.Response.Clear();
                    HttpContext.Current.Response.ContentType = "image/png";
                    ms.WriteTo(HttpContext.Current.Response.OutputStream);
                }
            }




        }

        /// <summary>
        /// Gets an image encoding codec for the given image MIME type.
        /// </summary>
        /// <param name="mimeType">The MIME type for the codec to get.</param>
        private static ImageCodecInfo GetCodec(string mimeType)
        {
            ImageCodecInfo codec = null;
            foreach (ImageCodecInfo e in ImageCodecInfo.GetImageEncoders())
            {
                if (e.MimeType == mimeType)
                {
                    codec = e;
                    break;
                }
            }
            return codec;
        }


        private Image ResizeImage( int newWidth, Image image)
        {
            var heightMultiplier = (float)image.Width/image.Height;
            return ResizeImage(newWidth, Convert.ToInt32(newWidth * heightMultiplier), image);

        }

        private Image ResizeImage(int newWidth, int newHeight, Image image)
        {
            var thumbnailBitmap = new Bitmap(newWidth, newHeight);

            var thumbnailGraph = Graphics.FromImage(thumbnailBitmap);

            thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
            thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
            thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;

            var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
            thumbnailGraph.DrawImage(image, imageRectangle);

            thumbnailGraph.Dispose();
            return thumbnailBitmap;
        }

        


        private void UpdateWordThumbnails(Stream fileStream)
        {
            using (var wpDocFile = WordprocessingDocument.Open(fileStream, true))
            {
                UpdateThumbnail(wpDocFile.ThumbnailPart, ThumbnailPartType.Wmf);
            }
        }
        
        private void UpdateWordTemplateThumbnails(Stream fileStream)
        {
            using (var wpDocTemplate = WordprocessingDocument.Open(fileStream, true))
            {
                UpdateThumbnail(wpDocTemplate.ThumbnailPart, ThumbnailPartType.Jpeg);
            }
        }

        private void UpdatePowerPointThumbnails(Stream fileStream)
        {
            using (var ppDocFile = PresentationDocument.Open(fileStream, true))
            {
                UpdateThumbnail(ppDocFile.ThumbnailPart, ThumbnailPartType.Jpeg);
            }
        }

        private void UpdateExcelThumbnails(Stream fileStream)
        {
            using (var xlDocFile = SpreadsheetDocument.Open(fileStream, true))
            {
                UpdateThumbnail(xlDocFile.ThumbnailPart, ThumbnailPartType.Wmf);
            }
        }

        public bool ThumbCallback()
        {
            return false;
        }
    }
}